from .util import do


class RGit:
    BRANCH_CURRENT = 1
    BRANCH_LOCAL = 2
    BRANCH_REMOTE = 3
    BRANCH_TYPE = (BRANCH_CURRENT, BRANCH_LOCAL, BRANCH_REMOTE)

    br_args_dict = {BRANCH_CURRENT: ['branch', '--no-color', '-v', '--abbrev=6', '--contains'],
                    BRANCH_LOCAL: ['branch', '--no-color', '-v', '--abbrev=6'],
                    BRANCH_REMOTE: ['branch', '--no-color', '-v', '--abbrev=6', '-r']}

    def __init__(self, repo: str):
        self._repo = repo

    def branch_list(self):
        dct = self.branch(RGit.BRANCH_REMOTE)
        for d in dct:
            d['branch_name'] = d['branch_name'].split('/')[-1]
        return dct

    def branch(self, br_type: int = BRANCH_LOCAL) -> []:
        args = ['git', '-C', self._repo] + RGit.br_args_dict[br_type]
        c = do(args)
        # parse the completed output
        lines = str(c.stdout, 'utf-8').split('\n')
        lines = [line.lstrip('*').strip() for line in lines if line
                 and 'origin/HEAD' not in line]
        o = []
        for line in lines:
            a = line.split()
            o.append({'branch_name': a[0], 'commit_id': a[1],
                      'commit': ' '.join(a[2:])})
        return o

    def stash(self):
        args = ['git', '-C', self._repo, 'stash']
        do(args)

    def stash_pop(self):
        args = ['git', '-C', self._repo, 'stash', 'pop']
        do(args)

    def restore_worktree(self):
        args = ['git', '-C', self._repo, 'checkout', '.']
        do(args)

    def switch_branch(self, br: str):
        sp = br.split('/')
        if len(sp) > 1 and 'origin' in sp:
            return self.fetch_remote_branch(br)
        else:
            remote = 'origin/' + br
            return self.fetch_remote_branch(remote)

    def switch_local_branch(self, local: str = None):
        args = ['git', '-C', self._repo, 'checkout', local]
        do(args)
        self.pull()

    def fetch_remote_branch(self, remote: str, local: str = None):
        if not local:
            local = remote.split('/')[1]
        cur_locals = self.branch(RGit.BRANCH_LOCAL)
        for l in cur_locals:
            if local == l['branch_name']:
                self.switch_local_branch(local)
                return
        self.restore_worktree()
        args = ['git', '-C', self._repo, 'checkout', '-b', local, remote]
        do(args)
        self.pull()

    def reset(self):
        args = ['git', '-C', self._repo, 'reset', 'HEAD', '--hard']
        do(args)

    def pull(self):
        args = ['git', '-C', self._repo, 'pull']
        do(args)

    def apply(self, patch: str):
        args = ['git', '-C', self._repo, 'apply', patch]
        do(args)

    def commit(self, m: str):
        args = ['git','-C', self._repo, 'commit',  '-a', '-m', m]
        do(args)

    def push(self):
        args = ['git','-C', self._repo, 'push']
        do(args)

    def config_name_and_email(self, name:str, email: str):
        args = ['git','-C', self._repo, 'config', 'user.name', name]
        do(args)
        args = ['git','-C', self._repo, 'config', 'user.email', email]
        do(args)

    def update(self):
        self.restore_worktree()
        self.pull()
